﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using HeritageAcademy.Models.Filters;
using HeritageAcademy.Models.ViewModels;


namespace HeritageAcademy.Library.Controls
{
    /// <summary>
    /// Interaction logic for Library
    /// </summary>
    public partial class LibraryView : UserControl
    {
        #region Parameters 
        
        LibraryViewModel viewModel;
        
        #endregion

        #region Ctor 

        public LibraryView()
        {
            InitializeComponent();
            this.DataContextChanged += new DependencyPropertyChangedEventHandler(LibraryView_DataContextChanged);
            LibraryBookView.GlobalAnimationStarted += new EventHandler(LibraryBookView_GlobalAnimationStarted);
            LibraryBookView.GlobalAnimationCompleted += new EventHandler(LibraryBookView_GlobalAnimationCompleted);
        }
        #endregion

        #region Event Handlers

        //private void BookListPanel_Loaded(object sender, RoutedEventArgs e)
        //{
        //    bookListPanel = sender as StackPanel;
        //}

        private void BookTitleItem_MouseEnter(object sender, MouseEventArgs e)
        {
            CourseViewModel bvm = (sender as FrameworkElement).DataContext as CourseViewModel;

            if (bvm != null)
            {
                UIElement element = BookItems.ItemContainerGenerator.ContainerFromItem(bvm) as UIElement;
                //if (element != null && bookListPanel != null)
                //{
                //    //bookListPanel.ScrollElementToCenter(element);
                //}
            }
        }

        private void FilterButton_MouseEnter(object sender, MouseEventArgs e)
        {
            CourseViewModel bvm = (sender as FrameworkElement).DataContext as CourseViewModel;
            if (bvm != null)
            {
                bvm.IsHighlighted = true;
            }
        }

        private void FilterButton_MouseLeave(object sender, MouseEventArgs e)
        {
            CourseViewModel bvm = (sender as FrameworkElement).DataContext as CourseViewModel;
            if (bvm != null)
            {
                bvm.IsHighlighted = true;
            }
        }

        private void LibraryBookView_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            CourseViewModel bvm = (sender as FrameworkElement).DataContext as CourseViewModel;
            if (bvm != null)
            {
                viewModel.HighlightedCourse = null;
                Navigator.Current.ShowCourseBoard(bvm);
            }
        }

        void LibraryView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            viewModel = this.DataContext as LibraryViewModel;
        }

        #endregion

        #region Public Methods 
        
        public void DoEntranceAnimation()
        {
            var enter = Resources["Enter"] as Storyboard;
            if (enter != null) enter.Begin(this);
        }

        public void DoExitAnimation()
        {
            var exit = Resources["Exit"] as Storyboard;
            if (exit != null) exit.Begin(this);
        }
        
        #endregion

        #region Navigation Sequence

        static Random R = new Random();
        CourseFilter lastSelectedFilter;

        private void FilterButton_Click(object sender, RoutedEventArgs e)
        {
            viewModel.HighlightedCourse = null;
            var filter = ((FrameworkElement)sender).DataContext as CourseFilter;
            if (filter == lastSelectedFilter) return;
            if (filter != null)
            {
                NavigateToFilter(filter);
            }
            else
            {
                var bvm = (sender as FrameworkElement).DataContext as CourseViewModel;
                Navigator.Current.ShowCourseBoard(bvm);
            }
        }

        private void NavigateToFilter(CourseFilter filter)
        {
            lastSelectedFilter = filter;
            FadeOutFilters();
        }

        private void FadeOutFilters()
        {
            if (FiltersList.Items.Count == 0)
            {
                // update the selected filter
                viewModel.PushOrPopToFilter(lastSelectedFilter);

                // fade in the new filter menu
                FadeInFilters();
            }

            else
            {
                var currentIndex = 0x0;
                bool isLast;
                Timeline lastAnimation = null;

                EventHandler handler = null;
                handler = delegate(object s, EventArgs e)
                {
                    // remove the handler 
                    lastAnimation.Completed -= handler;

                    // temporarily hide the list to avoid flashing
                    FiltersList.Visibility = Visibility.Hidden;

                    // update the selected filter
                    viewModel.PushOrPopToFilter(lastSelectedFilter);

                    // fade in the new filter menu
                    FadeInFilters();
                };

                foreach (var o in FiltersList.Items)
                {
                    var container = FiltersList.ItemContainerGenerator.ContainerFromItem(o) as FrameworkElement;

                    if (o == lastSelectedFilter)
                    {
                        var d = new DoubleAnimationUsingKeyFrames();

                        lastAnimation = d;
                        lastAnimation.Completed += handler;

                        d.KeyFrames.Add(new SplineDoubleKeyFrame { Value = 1, KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(600)) });
                        d.KeyFrames.Add(new SplineDoubleKeyFrame() { Value = 0, KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(800)) });
                        if (container != null) container.BeginAnimation(UIElement.OpacityProperty, d);
                    }
                    else
                    {
                        isLast = (currentIndex == FiltersList.Items.Count - 1);

                        // temporarily disable hit testing
                        container.IsHitTestVisible = false;

                        // set a transform on the ListBoxItem if it isn't already set (assume that any non-null value means it is properly set)
                        TranslateTransform t = ForceTranslateTransform(container, true);

                        // create a random start to that the animation feels staggered
                        int beginTime = R.Next(0, 9) * 25;

                        DoubleAnimationUsingKeyFrames translateAnimation = new DoubleAnimationUsingKeyFrames();
                        DoubleAnimationUsingKeyFrames opacityAnimation = new DoubleAnimationUsingKeyFrames();

                        if (isLast && (lastAnimation == null))
                        {
                            beginTime = 8 * 25;
                            lastAnimation = opacityAnimation;
                            lastAnimation.Completed += handler;
                        }

                        translateAnimation.KeyFrames.Add(new SplineDoubleKeyFrame() { Value = 0.0, KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(beginTime)) });
                        translateAnimation.KeyFrames.Add(new SplineDoubleKeyFrame() { Value = 40.0, KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(beginTime + 250)), KeySpline = new KeySpline(0.5, 0, 1, 0.75) });

                        opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame() { Value = 1, KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(beginTime)) });
                        opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame() { Value = 0, KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(beginTime + 250)), KeySpline = new KeySpline(0.5, 0, 1, 0.75) });

                        translateAnimation.FillBehavior = FillBehavior.HoldEnd;
                        opacityAnimation.FillBehavior = FillBehavior.HoldEnd;

                        t.BeginAnimation(TranslateTransform.YProperty, translateAnimation);
                        container.BeginAnimation(UIElement.OpacityProperty, opacityAnimation);
                    }

                    currentIndex++;
                }
            }
        }

        private void FadeInFilters()
        {
            // prep the items for animation
            foreach (object o in FiltersList.Items)
            {
                FrameworkElement container = FiltersList.ItemContainerGenerator.ContainerFromItem(o) as FrameworkElement;
                container.Opacity = 0.0;
            }

            // show the list again
            FiltersList.Visibility = Visibility.Visible;

            foreach (object o in FiltersList.Items)
            {
                FrameworkElement container = FiltersList.ItemContainerGenerator.ContainerFromItem(o) as FrameworkElement;
                // set a transform on the ListBoxItem if it isn't already set (assume that any non-null value means it is properly set)
                TranslateTransform t = ForceTranslateTransform(container, true);

                // create a random start to that the animation feels staggered
                int beginTime = R.Next(0, 7) * 35;

                // animate the translation

                DoubleAnimationUsingKeyFrames translateAnimation = new DoubleAnimationUsingKeyFrames();
                translateAnimation.KeyFrames.Add(new SplineDoubleKeyFrame() { Value = -40.0, KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(beginTime)) });
                translateAnimation.KeyFrames.Add(new SplineDoubleKeyFrame() { Value = 0.0, KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(beginTime + 300)), KeySpline = new KeySpline(0, 0.5, 0.5, 1) });

                DoubleAnimationUsingKeyFrames opacityAnimation = new DoubleAnimationUsingKeyFrames();
                opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame() { Value = 0, KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(beginTime)) });
                opacityAnimation.KeyFrames.Add(new SplineDoubleKeyFrame() { Value = 1, KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(beginTime + 300)) });


                EventHandler handler = null;
                handler = delegate(object s, EventArgs e)
                {
                    // remove the handler 
                    opacityAnimation.Completed -= handler;

                    // once the animate completes, we want to make sure it's hit testable
                    container.IsHitTestVisible = true;
                };

                opacityAnimation.Completed += handler;

                t.BeginAnimation(TranslateTransform.XProperty, translateAnimation);
                container.BeginAnimation(UIElement.OpacityProperty, opacityAnimation);
            }
        }

        private TranslateTransform ForceTranslateTransform(FrameworkElement element, bool resetValues)
        {
            TranslateTransform t = element.RenderTransform as TranslateTransform;
            if (t == null)
            {
                t = new TranslateTransform();
                element.RenderTransform = t;
            }

            if (resetValues)
            {
                t.X = 0;
                t.Y = 0;
            }

            return t;
        }

        #endregion

        void LibraryBookView_GlobalAnimationCompleted(object sender, EventArgs e)
        {
            BookList.IsAnimationEnabled = true;
        }

        void LibraryBookView_GlobalAnimationStarted(object sender, EventArgs e)
        {
            BookList.IsAnimationEnabled = false;
        }
    }
}
